home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pine / help.c < prev    next >
C/C++ Source or Header  |  1996-03-14  |  17KB  |  633 lines

  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: help.c,v 4.57 1996/03/15 07:13:42 hubert Exp $";
  3. #endif
  4. /*----------------------------------------------------------------------
  5.  
  6.             T H E    P I N E    M A I L   S Y S T E M
  7.  
  8.    Laurence Lundblade and Mike Seibel
  9.    Networks and Distributed Computing
  10.    Computing and Communications
  11.    University of Washington
  12.    Administration Builiding, AG-44
  13.    Seattle, Washington, 98195, USA
  14.    Internet: lgl@CAC.Washington.EDU
  15.              mikes@CAC.Washington.EDU
  16.  
  17.    Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  18.  
  19.  
  20.    Pine and Pico are registered trademarks of the University of Washington.
  21.    No commercial use of these trademarks may be made without prior written
  22.    permission of the University of Washington.
  23.  
  24.    Pine, Pico, and Pilot software and its included text are Copyright
  25.    1989-1996 by the University of Washington.
  26.  
  27.    The full text of our legal notices is contained in the file called
  28.    CPYRIGHT, included with this distribution.
  29.  
  30.  
  31.    Pine is in part based on The Elm Mail System:
  32.     ***********************************************************************
  33.     *  The Elm Mail System  -  Revision: 2.13                             *
  34.     *                                                                     *
  35.     *             Copyright (c) 1986, 1987 Dave Taylor              *
  36.     *             Copyright (c) 1988, 1989 USENET Community Trust   *
  37.     ***********************************************************************
  38.  
  39.  
  40.   ----------------------------------------------------------------------*/
  41.  
  42. /*======================================================================
  43.      help.c
  44.      Functions to support the pine help screens
  45.  ====*/
  46.  
  47.  
  48. #include "headers.h"
  49.  
  50. /*
  51.  * Internal prototypes
  52.  */
  53. void free_help_text PROTO((char **));
  54.  
  55.  
  56. #ifdef HELPFILE
  57. /*
  58.  * get_help_text - return the help text associated with index
  59.  *                 in an array of pointers to each line of text.
  60.  */
  61. char **
  62. get_help_text(index, pages)
  63. short index;
  64. int   *pages;
  65. {
  66.     int  i, current_page, len;
  67.     char buf[256], **htext, *tmp;
  68.     void copy_fix_keys();
  69.     struct hindx hindex_record;
  70.     FILE *helpfile;
  71. #if !defined(WIN32) && !defined(OS2)
  72.     extern long coreleft();
  73. #endif
  74.  
  75.     if(index < 0 || index >= LASTHELP)
  76.     return(NULL);
  77.  
  78.     /* make sure index file is available, and read appropriate record */
  79.     build_path(buf, ps_global->pine_dir, HELPINDEX);
  80.     if(!(helpfile = fopen(buf, "rb"))){
  81.     q_status_message1(SM_ORDER,3,5,
  82.         "No Help!  Index \"%s\" not found.", buf);
  83.     return(NULL);
  84.     }
  85.  
  86.     i = fseek(helpfile, index * sizeof(struct hindx), SEEK_SET) == 0
  87.      && fread((void *)&hindex_record,sizeof(struct hindx),1,helpfile) == 1;
  88.  
  89.     fclose(helpfile);
  90.     if(!i){    /* problem in fseek or read */
  91.         q_status_message(SM_ORDER, 3, 5,
  92.           "No Help!  Can't locate proper offset for help text file.");
  93.     return(NULL);
  94.     }
  95.  
  96. #if !defined(WIN32) && !defined(OS2)
  97.     if(coreleft() < (long)(80 * hindex_record.lines)){
  98.         q_status_message(SM_ORDER,3,5,
  99.         "No Help!  Not enough memory to display help.");
  100.     return(NULL);
  101.     }
  102. #endif
  103.  
  104.     /* make sure help file is open */
  105.     build_path(buf, ps_global->pine_dir, HELPFILE);
  106.     if((helpfile = fopen(buf, "rb")) == NULL){
  107.     q_status_message2(SM_ORDER,3,5,"No Help!  \"%s\" : %s", buf,
  108.               error_description(errno));
  109.     return(NULL);
  110.     }
  111.  
  112.     if(fseek(helpfile, hindex_record.offset, SEEK_SET) != 0
  113.        || fgets(buf, 255, helpfile) == NULL
  114.        || strncmp(hindex_record.key, buf, strlen(hindex_record.key))){
  115.     /* problem in fseek, or don't see key */
  116.         q_status_message(SM_ORDER, 3, 5,
  117.              "No Help!  Can't locate proper entry in help text file.");
  118.     fclose(helpfile);
  119.     return(NULL);
  120.     }
  121.  
  122.     htext = (char **)fs_get(sizeof(char *) * (hindex_record.lines + 1));
  123.     current_page = 0;
  124.     for(i=0; i < hindex_record.lines; i++){
  125.     if(fgets(buf, 255, helpfile) == NULL){
  126.         htext[i] = NULL;
  127.         free_help_text(htext);
  128.         fclose(helpfile);
  129.             q_status_message(SM_ORDER,3,5,"No Help!  Entry not in help text.");
  130.         return(NULL);
  131.     }
  132.  
  133.     if(*buf){
  134.         if((len = strlen(buf)) > 1
  135.            && (buf[len-2] == '\n' || buf[len-2] == '\r'))
  136.           buf[len-2] = '\0';
  137.         else if(buf[len-1] == '\n' || buf[len-1] == '\r')
  138.           buf[len-1] = '\0';
  139.     }
  140.     else
  141.       len = 0;
  142.  
  143.     htext[i] = NULL;
  144.     if(tmp = srchstr(buf, "___")){
  145.         if(!strcmp(tmp+3, "----")){
  146.         if(pages)
  147.           pages[current_page++] = i;
  148.         }
  149.         else if(!struncmp(tmp+3, "tdate", 5)){
  150.         char datebuf[128];
  151.         rfc822_date(datebuf);     /* let c-client do the work */
  152.         htext[i] = (char *)fs_get(strlen(buf) + strlen(datebuf));
  153.         strncpy(htext[i], buf, tmp - buf);
  154.         sprintf(htext[i] + (tmp - buf), "%s%s", datebuf, tmp + 8);
  155.         }
  156.         else if(!struncmp(tmp+3, "cdate", 5)){
  157.         extern char datestamp[];
  158.         htext[i] = (char *)fs_get(strlen(buf)+strlen(datestamp));
  159.         strncpy(htext[i], buf, tmp - buf);
  160.         sprintf(htext[i] + (tmp - buf), "%s%s", datestamp, tmp + 8);
  161.         }
  162.     }
  163.  
  164.     if(!htext[i]){
  165.         htext[i] = (char *)fs_get(len + 1);
  166.         copy_fix_keys(htext[i], buf);
  167.     }
  168.     }
  169.  
  170.     htext[i] = NULL;
  171.     if(pages != NULL)
  172.       pages[current_page] = -1;
  173.  
  174.     fclose(helpfile);
  175.     return(htext);
  176. }
  177. #endif    /* HELPFILE */
  178.  
  179.  
  180. /*
  181.  * free_help_text - free the strings and array of pointers pointed to 
  182.  *                  by text
  183.  */
  184. void
  185. free_help_text(text)
  186.     char **text;
  187. {
  188.     int i = 0;
  189.  
  190.     while(text[i])
  191.       fs_give((void **)&text[i++]);
  192.  
  193.     fs_give((void **)&text);
  194. }
  195.  
  196.  
  197.  
  198. /*----------------------------------------------------------------------
  199.      Make a copy of the help text for display, doing various substutions
  200.  
  201.   Args: a -- output string
  202.         b -- input string
  203.  
  204.  Result: string copied into buffer, and any expressions of the form
  205.  {xxx:yyy} are replaced by either xxx or yyy depending on whether
  206.  we are using function keys or not.  _'s are removed except for the
  207.  special case ^_, which is left as is.
  208.   ----*/
  209.  
  210. void 
  211. copy_fix_keys(a, b)
  212.   register char *a, *b;
  213. {
  214. #if defined(DOS) || defined(OS2)
  215.     register char *s = a;
  216. #endif
  217.     while(*b) {
  218.     while(*b && *b != '{')
  219.           if(*b == '^' && *(b+1) == '_') {
  220.               *a++ = *b++;
  221.               *a++ = *b++;
  222.       } else if(*b == '_' && *(b+1) == '_') {
  223.           while(*b == '_')
  224.         b++;
  225.       }
  226.       else
  227.         *a++ = *b++;
  228.  
  229.     if(*b == '\0') {
  230.         break;
  231.     }
  232.  
  233.     if(F_ON(F_USE_FK,ps_global)) {
  234.         if(*b)
  235.           b++;
  236.         while(*b && *b != ':')
  237.           *a++ = *b++;
  238.         while(*b && *b != '}')
  239.           b++;
  240.         if(*b)
  241.           b++;
  242.     } else {
  243.         while(*b && *b != ':')
  244.           b++;
  245.         if(*b)
  246.           b++;
  247.         while(*b && *b != '}')
  248.           *a++ = *b++;
  249.         if(*b)
  250.           b++;
  251.     }
  252.     }
  253.     *a = '\0';
  254. #if defined(DOS) || defined(OS2)
  255.     b = s;            /* eliminate back-slashes from "a" */
  256.     while(*s){
  257.     if(*s == '\\')
  258.       s++;
  259.  
  260.         *b++ = *s++;
  261.     }
  262.  
  263.     *b = '\0';            /* tie off back-slashed-string */
  264. #endif
  265. }
  266.  
  267.  
  268.  
  269. /*----------------------------------------------------------------------
  270.      Get the help text in the proper format and call scroller
  271.  
  272.     Args: text   -- The help text to display (from pine.help --> helptext.c)
  273.           title  -- The title of the help text 
  274.   
  275.   Result: format text and call scroller
  276.  
  277.   The pages array contains the line number of the start of the pages in
  278. the text. Page 1 is in the 0th element of the array.
  279. The list is ended with a page line number of -1. Line number 0 is also
  280. the first line in the text.
  281.   -----*/
  282. void
  283. #ifdef    HELPFILE
  284.  
  285. helper(text, title, from_composer)
  286.      short  text;
  287.      char   *title;
  288.      int    from_composer;
  289. {
  290.     char **new_text;
  291.  
  292.     if((new_text = get_help_text(text, NULL)) == NULL)
  293.       return;
  294.  
  295.     if(F_ON(F_BLANK_KEYMENU,ps_global)){
  296.     FOOTER_ROWS(ps_global) = 3;
  297.     clearfooter(ps_global);
  298.     ps_global->mangled_screen = 1;
  299.     }
  300.  
  301. #else
  302.  
  303. helper(text, title, from_composer)
  304.      char  *text[], *title;
  305.      int    from_composer;
  306. {
  307.     register char **t, **t2;
  308.     char          **new_text, *tmp;
  309.     int             pages[100], current_page, in_include;
  310.     char            *line, line_buf[256];
  311.     FILE           *file;
  312.     int            alloced_lines = 0;
  313.     int            need_more_lines = 0;
  314.  
  315.  
  316.     dprint(1, (debugfile, "\n\n    ---- HELPER ----\n"));
  317.  
  318.     if(F_ON(F_BLANK_KEYMENU,ps_global)){
  319.     FOOTER_ROWS(ps_global) = 3;
  320.     clearfooter(ps_global);
  321.     ps_global->mangled_screen = 1;
  322.     }
  323.  
  324.     if(from_composer){
  325.      fix_windsize(ps_global);
  326.     init_sigwinch();
  327.     }
  328.  
  329.     /*----------------------------------------------------------------------
  330.             First copy the help text and do substitutions
  331.       ----------------------------------------------------------------------*/
  332.  
  333.     for(t = text ; *t != NULL; t++);
  334.     alloced_lines = t - text;
  335.     new_text = (char **)fs_get((alloced_lines + 1) * sizeof(char *));
  336.  
  337.  
  338.     current_page = 0;
  339.     in_include   = 0;
  340.     file         = NULL;
  341.     for(t = text, t2 = new_text; *t != NULL;) {
  342.         int inc_line_cnt;
  343.         int lines_to_use = ps_global->ttyo->screen_rows
  344.                - HEADER_ROWS(ps_global) - FOOTER_ROWS(ps_global);
  345.         if(in_include) {
  346.             /*--- Inside an ___include ... ___end_include section ---*/
  347.             if(file != NULL) {
  348.  
  349.                 /*--- Read next line out of include file ---*/
  350.  
  351.         /* Add a page break every so often.  This is stupid in that
  352.          * it adds a page break even if there are no more lines.
  353.          */
  354.                 if(inc_line_cnt++ % lines_to_use == 0) {
  355.             /* this is a big long string, don't delete part of it */
  356.                     line = "                                                                         ___----";
  357.                 }else {
  358.                     line = fgets(line_buf, sizeof(line_buf), file);
  359.         }
  360.                 if(line == NULL) {
  361.                     fclose(file);
  362.                     in_include = 0;
  363.                     continue;
  364.                 }
  365.                 if(line[strlen(line)-1] == '\n')
  366.                     line[strlen(line)-1] = '\0';
  367.             } else {
  368.                 /*--- File wasn't there, copy the default text ---*/
  369.                 if(struncmp(*t, "___end_include", 14) == 0){
  370.                     in_include = 0;
  371.                     t++;
  372.                     continue;
  373.                 } else {
  374.                     line = *t;
  375.                 }
  376.             }
  377.         } else {
  378.             if(struncmp(*t, "___include", 10) == 0) {
  379.                 /*-- Found start of an ___include ... ___end_include block --*/
  380.                 char *p, *q, **pp;
  381.         int cnt;
  382.                 in_include = 1;
  383.                 inc_line_cnt = (current_page > 0)
  384.                           ? t2 - new_text - pages[current_page-1]
  385.                   : t2 - new_text;
  386.                 for(p = (*t)+10; *p && isspace(*p); p++);
  387.                 strcpy(line_buf, p);
  388.                 for(q = line_buf; *q && !isspace(*q); q++);
  389.                 *q = '\0';
  390.                 dprint(9, (debugfile, "About to open \"%s\"\n", line_buf));
  391.                 file = fopen(line_buf, "r");
  392.                 if(file != NULL) {
  393.           /*
  394.            * Calculate the size of the included file,
  395.            * might have to resize new_text.
  396.            */
  397.            for(cnt=0; fgets(line_buf, sizeof(line_buf), file) != NULL;
  398.                                    cnt++);
  399.                    /* add lines so we can insert page breaks if necessary */
  400.                    cnt = cnt + (inc_line_cnt-1+cnt)/(lines_to_use - 1);
  401.            /* rewind */
  402.            (void)fseek(file, 0L, 0);
  403.             /*
  404.              * Skip t forward to the end_include so that we know
  405.              * how many lines we're skipping.
  406.              */
  407.            pp = t;
  408.                    while(*t && struncmp(*t, "___end_include", 14) != 0)
  409.                      t++;
  410.            /* we need cnt more lines but freed up t-pp+1 lines */
  411.            need_more_lines += cnt - (t - pp + 1);
  412.            if(need_more_lines > 0) {
  413.              int offset = t2 - new_text;
  414.              alloced_lines += need_more_lines;
  415.              need_more_lines = 0;
  416.              fs_resize((void **)&new_text,
  417.                    (alloced_lines + 1) * sizeof(char *));
  418.              t2 = &new_text[offset];
  419.            }
  420.         }else {
  421.                   dprint(1, (debugfile,"Helptext Failed open \"%s\": \"%s\"\n",
  422.                              line_buf, error_description(errno)));
  423.         }
  424.                 t++;
  425.                 continue;
  426.             }  else {
  427.                 /*-- The normal case, just another line of help text ---*/
  428.                 line = *t;
  429.             }
  430.         }
  431.  
  432.         /*-- line now contains the text to use, where ever it came from --*/
  433.         dprint(9, (debugfile, "line-->%s<-\n", line));
  434.  
  435.     *t2 = NULL;
  436.     if(tmp = srchstr(line, "___")){
  437.         if(!strcmp(tmp+3, "----")){
  438.         pages[current_page++] = t2 - new_text;
  439.         }
  440.         else if(!struncmp(tmp+3, "tdate", 5)){
  441.         char datebuf[128];
  442.         rfc822_date(datebuf);     /* let c-client do the work */
  443.         *t2 = (char *)fs_get(strlen(line) + strlen(datebuf));
  444.         strncpy(*t2, line, tmp - line);
  445.         sprintf((*t2) + (tmp - line), "%s%s", datebuf, tmp + 8);
  446.         }
  447.         else if(!struncmp(tmp+3, "cdate", 5)){
  448.         extern char datestamp[];
  449.         *t2 = (char *)fs_get(strlen(line) + strlen(datestamp));
  450.         strncpy(*t2, line, tmp - line);
  451.         sprintf((*t2) + (tmp - line), "%s%s", datestamp, tmp + 8);
  452.         }
  453.     }
  454.  
  455.     if(!*t2){
  456.         *t2 = (char *)fs_get(strlen(line) + 1);
  457.         copy_fix_keys(*t2, line);
  458.     }
  459.  
  460.         t2++;
  461.     if(!in_include || (in_include && file == NULL))
  462.             t++;
  463.     }
  464.     *t2 = *t;
  465.     pages[current_page] = -1;
  466.  
  467.     dprint(7, (debugfile, "helper PAGE COUNT %d\n", current_page));
  468.     { int i;
  469.         for(i = 0 ; pages[i] != -1; i++) 
  470.          dprint(7, (debugfile, "helper PAGE %d line %d [%s]\n",i+1, pages[i],
  471.                     new_text[pages[i]]));
  472.     }
  473. #endif    /* HELPFILE */
  474.  
  475. #ifdef _WINDOWS
  476.     /* Under windows, throw the help text into a window. */
  477.     if (mswin_displaytext (title, NULL, 0, new_text, 0, 0) >= 0) 
  478.       return;
  479.     /* Buf if the window fails, fall through and display in main window. */
  480. #endif
  481.  
  482.     /* This is mostly here to get the curses variables for line and column
  483.         in sync with where the cursor is on the screen. This gets warped
  484.     when the composer is called because it does it's own stuff */
  485.     ClearScreen();
  486.     scrolltool((void *)new_text, title,
  487.                (text == main_menu_tx)
  488.              ? MainHelpText
  489.          : from_composer
  490.            ? ComposerHelpText
  491.            : HelpText,
  492.            CharStarStar, (ATTACH_S *)NULL);
  493.  
  494.     if(F_ON(F_BLANK_KEYMENU,ps_global))
  495.       FOOTER_ROWS(ps_global) = 1;
  496.  
  497.     ClearScreen();
  498.  
  499.     free_help_text(new_text);
  500. }
  501.  
  502.  
  503. void
  504. print_all_help()
  505. {
  506. #ifdef    HELPFILE
  507.     short t;
  508.     char **l, **h, buf[500];
  509. #else
  510.     char ***t, **l, buf[500];
  511. #endif
  512.     int     line_count;
  513.  
  514.     if(open_printer("all 50+ pages of help text ") == 0) {
  515. #ifdef    HELPFILE
  516.         for(t = 0; t < LASTHELP; t++) {
  517.         if((h = get_help_text(t, NULL)) == NULL){
  518.         return;
  519.             }
  520.             for(l = h; *l != NULL; l++) {
  521. #else
  522.         for(t = h_texts; *t != NULL; t++) {
  523.             line_count = 0;
  524.             for(l = *t; *l != NULL; l++) {
  525. #endif
  526.                 copy_fix_keys(buf, *l);
  527.                 print_text(buf);
  528.                 print_char('\n');
  529.                 line_count++;
  530.             }
  531.  
  532.             if(line_count <= 10){
  533.         print_text(NEWLINE);
  534.         print_text(NEWLINE);
  535.         }
  536.         else{
  537.         print_char(ctrl('L'));
  538.         print_text(NEWLINE);
  539.         }
  540.         }
  541.         close_printer();
  542.     }
  543. }
  544.  
  545.  
  546. #if defined(DOS) && !defined(_WINDOWS)
  547. #define NSTATUS 25  /* how many status messages to save for review */
  548. #else
  549. #define NSTATUS 100
  550. #endif
  551.  
  552. static char *stat_msgs[NSTATUS];
  553. static int   latest;
  554.  
  555. /*----------------------------------------------------------------------
  556.      Review last N status messages
  557.  
  558.     Args: title  -- The title of the screen
  559.   -----*/
  560. void
  561. review_messages(title)
  562.     char  *title;
  563. {
  564.     int             how_many = 0;
  565.     char          **tmp_text;
  566.     register char **e;
  567.     register int    i, j;
  568.  
  569.     e = stat_msgs;
  570.     tmp_text = (char **)fs_get((NSTATUS + 1) * sizeof(char *));
  571.  
  572.     /* allocate strings */
  573.     for(j = 0, i = latest+1; i < NSTATUS; i++)
  574.       if(e[i] && *e[i])
  575.     tmp_text[j++] = cpystr(e[i]);
  576.  
  577.     for(i = 0; i <= latest; i++)
  578.       if(e[i] && *e[i])
  579.     tmp_text[j++] = cpystr(e[i]);
  580.     
  581.     /* scrolltool expects NULL at end */
  582.     tmp_text[j] = NULL;
  583.     how_many = j;
  584.  
  585.     scrolltool((void *)tmp_text, title, ReviewMsgsText,
  586.     CharStarStar, (ATTACH_S *)NULL);
  587.  
  588.     /* free everything */
  589.     for(j = 0; j < how_many; j++)
  590.       fs_give((void **)&tmp_text[j]);
  591.  
  592.     fs_give((void **)&tmp_text);
  593. }
  594.  
  595.  
  596. /*----------------------------------------------------------------------
  597.      Add a message to the circular status message review buffer
  598.  
  599.     Args: message  -- The message to add
  600.   -----*/
  601. void
  602. add_review_message(message)
  603.     char *message;
  604. {
  605.     if(!(message && *message))
  606.       return;
  607.  
  608.     latest = (latest + 1) % NSTATUS;
  609.     if(stat_msgs[latest] && strlen(stat_msgs[latest]) >= strlen(message))
  610.       strcpy(stat_msgs[latest], message);  /* already enough space */
  611.     else{
  612.     if(stat_msgs[latest])
  613.       fs_give((void **)&stat_msgs[latest]);
  614.  
  615.     stat_msgs[latest] = cpystr(message);
  616.     }
  617. }
  618.  
  619.  
  620.  
  621. /*----------------------------------------------------------------------
  622.     Free resources associated with the status message review list
  623.  
  624.     Args: 
  625.   -----*/
  626. void
  627. end_status_review()
  628. {
  629.     for(latest = NSTATUS - 1; latest >= 0; latest--)
  630.       if(stat_msgs[latest])
  631.     fs_give((void **)&stat_msgs[latest]);
  632. }
  633.